package com.moxigua.iotbox.func;

import com.moxigua.iotbox.base.Constants;
import com.orhanobut.logger.Logger;

import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

public class MqttClientHepler {

    private MqttClient mMqttClient;
    private MqttConnectOptions mConnectOptions;
    private String mEndpoint;
    // 回调
    private MqttCallback mCallback;


    private MqttClientHepler() {
        mCallback = new MqttCallbackBus();
        try {
            TrustManagerFactory tmf = null;
            tmf = TrustManagerFactory.getInstance("X509");
            tmf.init((KeyStore) null);
            TrustManager[] trustManagers = tmf.getTrustManagers();
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, trustManagers, null);
            mConnectOptions = new MqttConnectOptions();
            mConnectOptions.setCleanSession(true);
            mConnectOptions.setSocketFactory(ctx.getSocketFactory());
        } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
            Logger.e(e,"连接出错");
            e.printStackTrace();
        }
    }

    private static class SingletonInstance {
        private static final MqttClientHepler INSTANCE = new MqttClientHepler();
    }

    public static MqttClientHepler getInstance() {
        return SingletonInstance.INSTANCE;
    }

    /**
     * 实例化mqtt客户端
     * @param endpoint
     * @param user
     * @param pass
     * @return
     * @throws MqttException
     */
    public MqttClient connect(String endpoint, String user, String pass) throws MqttException {

        if (mMqttClient != null && mMqttClient.isConnected()) {
            return mMqttClient;
        } else {
            MemoryPersistence persistence = new MemoryPersistence();
            mMqttClient = new MqttClient(endpoint, Constants.CLIENT_ID,persistence);
            mConnectOptions.setUserName(user);
            mConnectOptions.setPassword(pass.toCharArray());
            mMqttClient.setCallback(mCallback);
            mMqttClient.connect(mConnectOptions);
            return mMqttClient;
        }
    }

    public boolean isConnect() {
        if (mMqttClient != null && mMqttClient.isConnected()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 断开连接
     * @throws MqttException
     */
    public void disconnect() throws MqttException {
        if (mMqttClient != null && mMqttClient.isConnected()) {
            mMqttClient.disconnect();
            mMqttClient = null;
        }
    }

    /**
     * 向主题发布消息
     * @param topicName the name of the topic to publish to
     * @param qos       the quality of service to delivery the message at (0,1,2)
     * @param payload   the set of bytes to send to the MQTT server
     * @return boolean
     */
    public boolean publish(String topicName, int qos, byte[] payload) {
        boolean flag = false;
        if (mMqttClient != null && mMqttClient.isConnected()) {
            Logger.d("Publishing to topic \"" + topicName + "\" qos " + qos +"\n  payload is "+"\"" +new String(payload)+" \"");
            // Create and configure a message
            MqttMessage message = new MqttMessage(payload);
            message.setQos(qos);
            // Send the message to the server, control is not returned until
            // it has been delivered to the server meeting the specified
            // quality of service.
            try {
                mMqttClient.publish(topicName, message);
                flag = true;
            } catch (MqttException e) {
            }
        }
        return flag;
    }

    /**
     * 在服务器订阅主题
     * @param topicName 要订阅的主题名
     * @param qos   订阅的消息质量
     * @return
     */
    public boolean subscribe(String topicName, int qos) {
        boolean flag = false;
        if (mMqttClient != null && mMqttClient.isConnected()) {
            // Subscribe to the requested topic
            // The QoS specified is the maximum level that messages will be sent to the client at.
            // For instance if QoS 1 is specified, any messages originally published at QoS 2 will
            // be downgraded to 1 when delivering to the client but messages published at 1 and 0
            // will be received at the same level they were published at.
            Logger.d("Subscribing to topic \"" + topicName + "\" qos " + qos);
            try {
                mMqttClient.subscribe(topicName, qos);
                flag = true;
            } catch (MqttException e) {
            }
        }
        return flag;
    }

    /**
     * @return
     */
    public boolean subscribe() {
        return subscribe(Constants.TOPIC_SUB_REMOTE, 1);
    }

}